package br.com.affero.testewel.model.document;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;

import org.apache.commons.fileupload.FileUpload;
import org.apache.struts.upload.FormFile;

import br.com.affero.testewel.exception.ModelValidationException;
import br.com.affero.testewel.util.UploadUtil;

/**
 * Classe se alto nível concentrando todos os serviços relacionados à documentos.
 * Abstrai o acesso a Utils, Validators, DAOs...
 * 
 * Padrão Façade
 * @see http://c2.com/cgi/wiki?FacadePattern
 * 
 * @author Welington veiga
 * @since 20/12/2011
 *
 */
public class DocumentService {

	private final DocumentDAO dao;
	
	
	
	/**
	 * Instância única do Serviço de Documentos
	 */
	private static DocumentService instance;
	
	public static DocumentService getInstance(){
		// Vamos construir caso não exista o/
		if(instance == null)
			instance = new DocumentService();
		
		return instance;
	}
	
	/**
	 * Construtor privado.
	 * OBS: Adicionei a obtenção de DAOs, Validators, Util aqui para evitar 
	 * construção dos objetos estaticamente, pelo ClassLoader.
	 * Assim, se uma instancia do serviço não for obtida nenhuma das dependências será construída.
	 * 
	 *  @todo Implementar uma forma abstrata de realizar a instanciação dos compenentes necessário. Via configuração XML, Factories ou DI, por exemplo.
	 */
	private DocumentService(){
		dao = new DocumentHibernateDAO();
	}
	
	/**
	 * Método que obtem todos os documentos cadastrados.
	 * @return lista de Documentos
	 */
	public List<Document> getAll(){
		return dao.listAll();
	}

	/**
	 * Método que obtem 1 Document pelo id, ou null caso ele não seja encontrado. 
	 * @param id
	 * @return
	 */
	public Document findById(Long id) {
		return dao.findOneById(id);
	}

	/**
	 * Método que salva um Document, atualizando um Document pré-existente ou inserindo caso este não exista.
	 * @param document
	 * @param formFile 
	 * @param destination 
	 * @throws Exception 
	 */
	public void save(Document document, FormFile formFile, String destination) throws Exception{
		final UploadUtil uploader = UploadUtil.getInstance();
		String finalName = null;
		try{
			// 1 - Validamos o Objeto
			/**@todo fica pra próxima, infelizmente não da tempo...*/

			// 2 - Salvamos o upload
			finalName= uploader.write(new File(destination), formFile);
			if(formFile != null && formFile.getFileSize() > 0){
				document.setPath(finalName);
				document.setSize(formFile.getFileSize());
				document.setUploadedAt(new Date());
			}
			// 3 - Tentamos persistir o objteto
			dao.persist(document);
		}catch (Exception e) {
			// se algo falhar, vamos apagar o arquivo.
			if(finalName != null && new File(finalName).exists())
				uploader.delete(finalName);
			throw e;
		}
	}
	
	/**
	 * Método que deleta um documento, apagando seu arquivo anexado também.
	 * @param parseLong
	 * @return
	 */
	public void delete(Long id) {
		Document doc = dao.findOneById(id);
		if(doc == null)
			return;
		// 1 Vamos apagar do banco
		dao.delete(doc);		
		// 2 Vamos apagar do disco
		UploadUtil.getInstance().delete(doc.getPath());
	}
	
	
}
